package role

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"strings"

	"github.com/patrickmn/go-cache"
)

// 设计逻辑参照casbin架构：https://gitee.com/mirrors/casbin

const (
	ACT_RES_READ   int8 = 1 // 针对资源型客体
	ACT_RES_WRITE  int8 = 2 // 针对资源型客体
	ACT_API_ACCESS int8 = 3 // 针对接口型客体

	OBJ_TYPE_RES objType = 1 // 客体类型：资源
	OBJ_TYPE_API objType = 2 // 客体类型：接口
)

var (
	SECURITY_POLICY_CACHE *cache.Cache        = cache.New(0, 0)
	policyDictionary      map[string][]Policy = map[string][]Policy{}
)

// 客体类型
type objType int8

// 操作
// type act int8

// 权限
type Policy struct {
	Sub     string  `json:"sub"`     // 主体，标签值
	ObjType objType `json:"objType"` // 客体类型
	Obj     string  `json:"obj"`     // 客体
	Act     int8    `json:"act"`     // 操作
}

func (p *Policy) Match(dest *Policy) bool {
	if dest.ObjType == OBJ_TYPE_API {
		return p.Sub == dest.Sub && strings.EqualFold(p.Obj, dest.Obj) && p.Act == dest.Act
	}
	return p.Sub == dest.Sub && strings.EqualFold(p.Obj, dest.Obj) && p.Act >= dest.Act // 资源的权限，如果有写权限，则包含读权限
}

func PolicyCacheKey(act int8, obj string) string {
	return fmt.Sprintf("%s::%d::%s", "policy_cache", act, obj)
}

func GetPolicy(obj string, act int8) (*Policy, bool) {
	r, b := SECURITY_POLICY_CACHE.Get(PolicyCacheKey(act, obj))
	if !b {
		return nil, false
	}
	tmp := r.(Policy)
	return &tmp, true
}

func SetPolicy(p Policy) {
	SECURITY_POLICY_CACHE.SetDefault(PolicyCacheKey(p.Act, p.Obj), p)
	policyDictionary[p.Sub] = append(policyDictionary[p.Sub], p)
}

func GetAllPolicy() map[string][]Policy {
	var buf bytes.Buffer
	gob.NewEncoder(&buf).Encode(policyDictionary)
	var tmp map[string][]Policy
	gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(&tmp)
	return tmp
}
